package com.onesports.intelligent.k12.polarlight.service.grade;

import static com.onesports.intelligent.k12.polarlight.common.utils.DateUtils.HH_MM;
import static com.onesports.intelligent.k12.polarlight.common.utils.DateUtils.YYYY_MM_DD;
import static com.onesports.intelligent.k12.polarlight.common.utils.DateUtils.between;
import static com.onesports.intelligent.k12.polarlight.common.utils.DateUtils.date2LocalDate;
import static com.onesports.intelligent.k12.polarlight.common.utils.DateUtils.format;
import static com.onesports.intelligent.k12.polarlight.common.utils.DateUtils.getDays;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.onesports.framework.kit.common.util.BeanUtils;
import com.onesports.framework.kit.common.util.ParamUtils;
import com.onesports.framework.kit.common.util.TimeUtils;
import com.onesports.intelligent.k12.polarlight.common.constant.Constants;
import com.onesports.intelligent.k12.polarlight.common.errors.exceptions.BusinessException;
import com.onesports.intelligent.k12.polarlight.common.utils.DateUtils;
import com.onesports.intelligent.k12.polarlight.domain.dto.cls.ClassPageDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.course.DisbandClassDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.course.DissolutionClassDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.course.SpellingClassDetailsDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.market.UploadMienDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.organization.CampusIdDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.student.RemoveStudentDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.wx.CoachEvaluateDTO;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.ClassInfo;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.ClassMien;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.ClassStudent;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.CourseSchedule;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.CourseScheduleDetail;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.CourseScheduleDetailCoachRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.SpellingClassDetails;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.SpellingClassPeriod;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.EducationEvaluationRecord;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.Orders;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.Product;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.ProductCampusRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.organization.Coach;
import com.onesports.intelligent.k12.polarlight.domain.entity.organization.CoachCampusRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.organization.OrganizationStaff;
import com.onesports.intelligent.k12.polarlight.domain.entity.student.Student;
import com.onesports.intelligent.k12.polarlight.domain.entity.student.StudentAttendance;
import com.onesports.intelligent.k12.polarlight.domain.entity.student.UserStudentRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.sys.WxUser;
import com.onesports.intelligent.k12.polarlight.domain.entity.sys.WxUserPurse;
import com.onesports.intelligent.k12.polarlight.domain.vo.cls.ClassDetailVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.cls.ClassPageVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.cls.ClassWxDetailVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.cls.ClassWxPageVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.cls.CoachClassPageVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.cls.SellClaRuleInfoVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.ClassMienVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.ClassScheduleVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.MineSpellClassVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.NearSpellClassVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.SpellClassInfoVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.WeChatUserVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.product.ProductMinPriceVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.student.StudentVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.wx.CoachEvaluateVO;
import com.onesports.intelligent.k12.polarlight.enums.AttendanceStatusEnum;
import com.onesports.intelligent.k12.polarlight.enums.ClassInfoStatusEnum;
import com.onesports.intelligent.k12.polarlight.enums.MessageTypeEnum;
import com.onesports.intelligent.k12.polarlight.enums.OrderStatusEnum;
import com.onesports.intelligent.k12.polarlight.enums.ScheduleDetailStatusEnum;
import com.onesports.intelligent.k12.polarlight.enums.SpellingClassPeriodEnum;
import com.onesports.intelligent.k12.polarlight.enums.SysConfigTypeEnum;
import com.onesports.intelligent.k12.polarlight.mapper.course.ClassInfoMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.ClassMienMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.ClassStudentMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseScheduleDetailCoachRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseScheduleDetailMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseScheduleMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.ScheduleDetailCoachRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.SpellingClassDetailsMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.EducationEvaluationRecordMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.ProductCampusRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.ProductMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.ProductSellPriceRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.organization.CoachCampusRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.organization.CoachMapper;
import com.onesports.intelligent.k12.polarlight.mapper.organization.OrganizationStaffMapper;
import com.onesports.intelligent.k12.polarlight.mapper.student.StudentAttendanceMapper;
import com.onesports.intelligent.k12.polarlight.mapper.student.StudentMapper;
import com.onesports.intelligent.k12.polarlight.mapper.student.UserStudentRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.sys.WxUserMapper;
import com.onesports.intelligent.k12.polarlight.security.SecurityUtils;
import com.onesports.intelligent.k12.polarlight.service.course.CourseScheduleDetailService;
import com.onesports.intelligent.k12.polarlight.service.course.SpellingClassPeriodService;
import com.onesports.intelligent.k12.polarlight.service.order.OrderService;
import com.onesports.intelligent.k12.polarlight.service.student.ClassStudentService;
import com.onesports.intelligent.k12.polarlight.service.student.WxUserService;
import com.onesports.intelligent.k12.polarlight.service.sys.ConfigService;
import com.onesports.intelligent.k12.polarlight.service.sys.MessageNotifyService;
import com.onesports.intelligent.k12.polarlight.service.wx.WxUserPurseService;
import com.onesports.intelligent.k12.polarlight.util.BeanCopyUtil;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 班级
 *
 * @author clw
 * @date 2022-07-11 11:06:18
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ClassInfoService extends ServiceImpl<ClassInfoMapper, ClassInfo> {

    private final ClassInfoMapper classInfoMapper;
    private final ClassStudentMapper classStudentMapper;
    private final WxUserMapper wxUserMapper;
    private final StudentMapper studentMapper;
    private final SpellingClassDetailsMapper spellingClassDetailsMapper;
    private final ScheduleDetailCoachRelMapper scheduleDetailCoachRelMapper;
    private final CoachCampusRelMapper coachCampusRelMapper;
    private final CoachMapper coachMapper;
    private final OrganizationStaffMapper organizationStaffMapper;
    private final ProductMapper productMapper;
    private final WxUserService wxUserService;
    private final ClassStudentService classStudentService;
    private final StudentAttendanceMapper studentAttendanceMapper;

    private final ClassMienMapper classMienMapper;

    private final EducationEvaluationRecordMapper educationEvaluationRecordMapper;

    private final CourseScheduleDetailMapper courseScheduleDetailMapper;

    private final OrderService orderService;
    private final SpellingClassPeriodService spellingClassPeriodService;
    private final CourseScheduleDetailCoachRelMapper courseScheduleDetailCoachRelMapper;
    private final MessageNotifyService messageNotifyService;

    private final CourseScheduleDetailService courseScheduleDetailService;
    private final CourseScheduleMapper courseScheduleMapper;

    private final UserStudentRelMapper userStudentRelMapper;

    private final WxUserPurseService wxUserPurseService;

    private final ConfigService configService;

    private final ProductCampusRelMapper productCampusRelMapper;

    private final ProductSellPriceRelMapper productSellPriceRelMapper;


    private static final String CANCEL_REASON = "退出学员导致学员人数小于最小上课人数，课表作废";

    /**
     * 附近拼班列表
     *
     * @param dto dto
     * @return {@link List}<{@link NearSpellClassVO}>
     */
    public List<NearSpellClassVO> nearSpellClassList(CampusIdDTO dto) {

        //根据校区Id查询拼班信息
        List<NearSpellClassVO> list = classInfoMapper.getNearSpellClassList(dto);
        Date date = new Date();
        Date currentDate = TimeUtils.toDate(TimeUtils.toText(date, TimeUtils.DATE_FORMAT), TimeUtils.DATE_FORMAT);

        if (ParamUtils.isNotEmpty(list)) {

            //判断是否满足最高人数限制,满足则过滤掉
            list = list.stream().filter(psc -> psc.getUseStudentNum().compareTo(psc.getMaxNum()) != 0).collect(Collectors.toList());
            //查询学员信息
            List<WeChatUserVO> weChatUserList = studentMapper.findAllStudent();
            Map<String,List<WeChatUserVO>> weChatUserMap = weChatUserList.stream().collect(Collectors.groupingBy(WeChatUserVO::getClassInfoId));
            for (NearSpellClassVO nearSpellClassVO : list) {

                SpellingClassPeriod earliestPeriod = this.spellingClassPeriodService.getEarliestCurrentPeriod(nearSpellClassVO.getClassInfoId(), currentDate);
                if(ParamUtils.isEmpty(earliestPeriod)){
                    list = list.stream().filter(nsc-> !nsc.getClassInfoId().equals(nearSpellClassVO.getClassInfoId()) ).collect(Collectors.toList());
                }

                if(ParamUtils.isNotEmpty(weChatUserMap)){
                    nearSpellClassVO.setWeChatUserList(weChatUserMap.get(nearSpellClassVO.getClassInfoId()));
                }

            }
        }

        return list;
    }

    /**
     * 构造学员数据
     *
     * @param nearSpellClassVO 拼班VO
     * @param classStudents    班级学生
     */
    private void extractedStudent(NearSpellClassVO nearSpellClassVO, List<ClassStudent> classStudents) {
        //获取学生Id
        List<String> studentIds = classStudents.stream().map(ClassStudent::getStudentId).collect(Collectors.toList());
        LambdaQueryWrapper<Student> studentWrappers = new LambdaQueryWrapper<>();
        studentWrappers.in(Student::getId, studentIds);
        List<Student> studentList = studentMapper.selectList(studentWrappers);
        List<WeChatUserVO> weChatUserList = new ArrayList<>();
        for (Student student : studentList) {
            WeChatUserVO vo = new WeChatUserVO();
            vo.setStudentId(student.getId());
            vo.setAvatar(student.getAvatar());
            weChatUserList.add(vo);
        }
        nearSpellClassVO.setWeChatUserList(weChatUserList);
    }

    /**
     * 发起拼班
     *
     * @param dto dto
     * @return {@link String}
     */
    @Transactional(rollbackFor = Exception.class)
    public String initiateSpellClassList(SpellingClassDetailsDTO dto) {

        // 根据当前时间、时段和课表Id查询course_schedule_detail获取主键Id
        Date date = new Date();
        log.info("开始时段:{} 结束时段:{}",dto.getStartPeriod(),dto.getEndPeriod());
        // 取第一条数据
        CourseScheduleDetail courseScheduleDetail = courseScheduleDetailMapper.getCourseScheduleDetail(TimeUtils.toText(date),dto.getScheduleId(),dto.getStartPeriod(),dto.getEndPeriod());
        if(ParamUtils.isEmpty(courseScheduleDetail)){
            throw new BusinessException("本周期无课表了,不支持拼班");
        }
        //获取课表详情list
        List<CourseScheduleDetail> courseScheduleDetailList = courseScheduleDetailMapper.getCourseScheduleDetailList(TimeUtils.toText(date),dto.getScheduleId(),dto.getStartPeriod(),dto.getEndPeriod());
        List<String> ids = courseScheduleDetailList.stream().map(CourseScheduleDetail::getId).collect(Collectors.toList());
        //根据课表时段明细表Id 查询课表时段详情关联教练表 获取教练
        LambdaQueryWrapper<CourseScheduleDetailCoachRel> csdWra = new LambdaQueryWrapper<>();
        csdWra.in(CourseScheduleDetailCoachRel::getScheduleDetailId, ids);
        csdWra.eq(CourseScheduleDetailCoachRel::getStatus, Boolean.TRUE);
        List<CourseScheduleDetailCoachRel> csdcList = scheduleDetailCoachRelMapper.selectList(csdWra);
        if (ParamUtils.isEmpty(csdcList)) {
            throw new BusinessException("该时段已售空，请选择其他时段拼班！");
        }

        List<String> coachIds = csdcList.stream().map(CourseScheduleDetailCoachRel::getCoachId).collect(Collectors.toList());
        //根据教练Id和校区Id查询 教练社区(校区)关联表 根据排序号获取教练
        LambdaQueryWrapper<CoachCampusRel> ccrWra = new LambdaQueryWrapper<>();
        ccrWra.eq(CoachCampusRel::getCampusId, dto.getCampusId());
        ccrWra.in(CoachCampusRel::getCoachId, coachIds);
        List<CoachCampusRel> ccrList = coachCampusRelMapper.selectList(ccrWra);
        //取序号最小的数据
        CoachCampusRel coachCampusRel = ccrList.stream().min(Comparator.comparing(CoachCampusRel::getQueueNumber)).get();
        //根据教练Id查询教练信息
        Coach coach = coachMapper.selectById(coachCampusRel.getCoachId());
        OrganizationStaff os = organizationStaffMapper.selectById(coach.getOrganizationStaffId());

        //创建班级
        ClassInfo classInfo = getClassInfo(dto, courseScheduleDetailList, coachCampusRel, os);

        //创建班级拼班时段表信息
        List<SpellingClassPeriod> spellingClassPeriodList = getSpellingClassPeriods(date, courseScheduleDetailList, classInfo);

        //创建拼班明细表
        createSpellClassDetail(dto, courseScheduleDetail, classInfo, spellingClassPeriodList);

        //根据教练Id和时段和课程日期(周期如:如13--15号)
        String startDate = dto.getStartDate();
        String endDate = dto.getEndDate();
        List<String> cycle = getDays(startDate,endDate);
        //更新教练状态
        courseScheduleDetailCoachRelMapper.updateCoachRelStatus(coach.getId(),dto.getStartPeriod(),dto.getEndPeriod(),cycle,false);

        //课表时段详情关联教练表
        //根据课表Id和时段查询course_schedule_detail获取主键Id
        //更新当前时段--课表时段详情关联教练表状态
        //currentPeriod(dto, coachCampusRel);



        //时段 教练交集需要过滤掉(如：09:00--10:00 09:30--10:30,10:30--11:00 13:00--14:00)
        //查询出不等于当前时段的其它数据
        //List<SchedulePeriodDetailVO> schedulePeriodDetailVOList = courseScheduleDetailMapper.getSchedulePeriodDetailList(dto.getScheduleId(),dto.getStartPeriod(),dto.getEndPeriod());
        //
        //List<Map<String, String>> result = new ArrayList<>();
        //if(ParamUtils.isNotEmpty(schedulePeriodDetailVOList)){
        //    Map<String, String> map1 = new HashMap<>();
        //    map1.put("startTime", dto.getStartPeriod());
        //    map1.put("endTime", dto.getEndPeriod());
        //    for (SchedulePeriodDetailVO schedulePeriodDetailVO : schedulePeriodDetailVOList) {
        //        Map<String, String> map2 = new HashMap<>();
        //        map2.put("startTime", TimeUtils.toText(schedulePeriodDetailVO.getStartTime(),HH_MM));
        //        map2.put("endTime", TimeUtils.toText(schedulePeriodDetailVO.getEndTime(),HH_MM));
        //        result.add(map2);
        //    }
        //    //List<SchedulePeriodDetailDTO> spddList = new ArrayList<>();
        //    //获取交集数据
        //    List<Map<String, String>> listMap = TimeSlotUtil.getMaps(result,map1);
        //    if(ParamUtils.isNotEmpty(listMap)){
        //        for (Map<String, String> stringMap : listMap) {
        //            String startTime = stringMap.get("startTime");
        //            String endTime = stringMap.get("endTime");
        //
        //            ///根据课表Id和时段查询course_schedule_detail获取主键Id
        //            List<CourseScheduleDetail> csdList = courseScheduleDetailMapper.getScheduleDetailCoachList(dto.getScheduleId(),startTime,endTime);
        //            if(ParamUtils.isNotEmpty(csdList)){
        //                List<String> scheduleDetailIds = csdList.stream().map(CourseScheduleDetail::getId).collect(Collectors.toList());
        //                LambdaQueryWrapper<CourseScheduleDetailCoachRel> relWra = new LambdaQueryWrapper<>();
        //                relWra.in(CourseScheduleDetailCoachRel::getScheduleDetailId,scheduleDetailIds);
        //                relWra.eq(CourseScheduleDetailCoachRel::getCoachId,coachCampusRel.getCoachId());
        //                List<CourseScheduleDetailCoachRel> csdRelList = courseScheduleDetailCoachRelMapper.selectList(relWra);
        //                if(ParamUtils.isNotEmpty(csdRelList)){
        //                    for (CourseScheduleDetailCoachRel courseScheduleDetailCoachRel : csdRelList) {
        //                        //更新状态
        //                        courseScheduleDetailCoachRel.setStatus(Boolean.FALSE);
        //                        courseScheduleDetailCoachRelMapper.updateById(courseScheduleDetailCoachRel);
        //                    }
        //                }
        //            }
        //        }
        //    }
        //}
        return classInfo.getId();
    }

    /**
     * 更新当前时段--课表时段详情关联教练表
     *
     * @param dto            dto
     * @param coachCampusRel 教练校园rel
     */
    private void currentPeriod(SpellingClassDetailsDTO dto, CoachCampusRel coachCampusRel) {
        List<CourseScheduleDetail>
            coachRelList = courseScheduleDetailMapper.getScheduleDetailCoachList(dto.getScheduleId(),dto.getStartPeriod(),dto.getEndPeriod());
        if(ParamUtils.isNotEmpty(coachRelList)){
            List<String> scheduleIds = coachRelList.stream().map(CourseScheduleDetail::getId).collect(Collectors.toList());
            LambdaQueryWrapper<CourseScheduleDetailCoachRel> coachRelWra = new LambdaQueryWrapper<>();
            coachRelWra.in(CourseScheduleDetailCoachRel::getScheduleDetailId,scheduleIds);
            coachRelWra.eq(CourseScheduleDetailCoachRel::getCoachId,coachCampusRel.getCoachId());
            List<CourseScheduleDetailCoachRel> relList = courseScheduleDetailCoachRelMapper.selectList(coachRelWra);
            if(ParamUtils.isNotEmpty(relList)){
                for (CourseScheduleDetailCoachRel courseScheduleDetailCoachRel : relList) {
                    //更新状态
                    courseScheduleDetailCoachRel.setStatus(Boolean.FALSE);
                    courseScheduleDetailCoachRelMapper.updateById(courseScheduleDetailCoachRel);
                }
            }
        }
    }

    /**
     * 拼班详情
     *
     * @param dto                     dto
     * @param courseScheduleDetail    课程安排细节
     * @param classInfo               班级
     * @param spellingClassPeriodList 拼班时段列表
     */
    private void createSpellClassDetail(SpellingClassDetailsDTO dto, CourseScheduleDetail courseScheduleDetail, ClassInfo classInfo,
        List<SpellingClassPeriod> spellingClassPeriodList) {
        SpellingClassDetails scd = new SpellingClassDetails();
        scd.setProductSellPriceRelId(dto.getProductSellPriceRelId());
        scd.setPrice(dto.getPrice());
        scd.setSpellType(dto.getSpellType());
        scd.setNum(ParamUtils.isNotEmpty(spellingClassPeriodList)? spellingClassPeriodList.size():0);
        scd.setScheduleId(dto.getScheduleId());
        scd.setStartDate(TimeUtils.toDate(dto.getStartDate()));
        scd.setEndDate(TimeUtils.toDate(dto.getEndDate()));
        scd.setStartPeriod(TimeUtils.toDate(dto.getStartPeriod(),HH_MM));
        scd.setEndPeriod(TimeUtils.toDate(dto.getEndPeriod(),HH_MM));
        scd.setClassInfoId(classInfo.getId());
        scd.setCourseScheduleDetailId(courseScheduleDetail.getId());
        spellingClassDetailsMapper.insert(scd);
    }

    /**
     * 创建班级拼班时段表信息
     *
     * @param date                     日期
     * @param courseScheduleDetailList 课表列表
     * @param classInfo                班级
     * @return {@link List}<{@link SpellingClassPeriod}>
     */
    private List<SpellingClassPeriod> getSpellingClassPeriods(Date date,
        List<CourseScheduleDetail> courseScheduleDetailList, ClassInfo classInfo) {
        List<SpellingClassPeriod> spellingClassPeriodList = new ArrayList<>();
        if (ParamUtils.isNotEmpty(courseScheduleDetailList)) {
            for (CourseScheduleDetail scheduleDetail : courseScheduleDetailList) {
                if (!date.before(scheduleDetail.getCourseDate())) {
                    // 过期
                    SpellingClassPeriod scp = new SpellingClassPeriod();
                    scp.setClassInfoId(classInfo.getId());
                    scp.setCourseScheduleDetailId(scheduleDetail.getId());
                    scp.setStatus(Constants.EXPIRED);
                    scp.setStartTime(scheduleDetail.getStartTime());
                    scp.setEndTime(scheduleDetail.getEndTime());
                    scp.setCourseDate(scheduleDetail.getCourseDate());
                    spellingClassPeriodList.add(scp);

                } else {
                    // 未过期
                    SpellingClassPeriod scp = new SpellingClassPeriod();
                    scp.setClassInfoId(classInfo.getId());
                    scp.setCourseScheduleDetailId(scheduleDetail.getId());
                    scp.setStatus(Constants.NOT_EXPIRED);
                    scp.setStartTime(scheduleDetail.getStartTime());
                    scp.setEndTime(scheduleDetail.getEndTime());
                    scp.setCourseDate(scheduleDetail.getCourseDate());
                    spellingClassPeriodList.add(scp);
                }
            }
        }
        spellingClassPeriodService.saveBatch(spellingClassPeriodList);
        return spellingClassPeriodList;
    }

    /**
     * 创建班级
     *
     * @param dto                      dto
     * @param courseScheduleDetailList 课程列表
     * @param coachCampusRel           教练校园rel
     * @param os                       职工
     * @return {@link ClassInfo}
     */
    private ClassInfo getClassInfo(SpellingClassDetailsDTO dto, List<CourseScheduleDetail> courseScheduleDetailList,
        CoachCampusRel coachCampusRel, OrganizationStaff os) {
        ClassInfo classInfo = new ClassInfo();
        classInfo.setCourseId(dto.getCourseId());
        //班级名称: 课表名称+教练姓名
        classInfo.setClassName(dto.getScheduleName() + "(" + os.getStaffName() + ")");
        classInfo.setCoachId(coachCampusRel.getCoachId());
        classInfo.setCampusId(dto.getCampusId());
        //团长Id
        classInfo.setWxUserId(SecurityUtils.getAccountId());
        classInfo.setClassStatus(ClassInfoStatusEnum.IN_CLASS.getValue());
        classInfo.setCourseNum(ParamUtils.isNotEmpty(courseScheduleDetailList)? courseScheduleDetailList.size():0);
        LambdaQueryWrapper<ProductCampusRel> productWra = new LambdaQueryWrapper<>();
        productWra.eq(ProductCampusRel::getProductId,dto.getProductId());
        productWra.eq(ProductCampusRel::getCampusId,dto.getCampusId());
        productWra.eq(ProductCampusRel::getDeleted,Boolean.FALSE);
        ProductCampusRel product = productCampusRelMapper.selectOne(productWra);
        classInfo.setOrganizationId(product.getOrganizationId());
        classInfo.setProductId(dto.getProductId());
        this.save(classInfo);
        return classInfo;
    }

    /**
     * 机构端班级管理获取分页列表
     *
     * @return
     */
    public IPage<ClassPageVO> getPage(ClassPageDTO dto) {
        Page<ClassPageVO> classDetailVOPage = new Page<>(dto.getPage(), dto.getRow());
        return classInfoMapper.getClassDetail(classDetailVOPage, dto, SecurityUtils.getOrganizationId());
    }

    /**
     * 机构端获取班级信息
     *
     * @return
     */
    public ClassDetailVO getClassDetail(String classId) {
        ClassDetailVO resultList = classInfoMapper.getDetailByClassId(classId,SecurityUtils.getOrganizationId());
        if (resultList == null) {
            return null;
        }
        resultList.setStudentList(classStudentMapper.getStudentByClassId(classId));
        //拼班中不显示班级排课表
        if (!resultList.getClassStatus().equals(ClassInfoStatusEnum.IN_CLASS.getValue())
            && !resultList.getClassStatus().equals(ClassInfoStatusEnum.FAIL_CLASS.getValue())){
            resultList.setCourseList(courseScheduleDetailService.getScheduleDetail(classId));
        }
        return resultList;
    }

    public List<SpellClassInfoVO> spellClassInfo(List<String> scheduleDetailIds, String coachId) {
        return this.classInfoMapper.spellClassInfo(scheduleDetailIds, ScheduleDetailStatusEnum.CANCEL.getValue(), coachId);
    }

    public MineSpellClassVO getMineSpellClass(String classInfoId) {

        MineSpellClassVO msc = new MineSpellClassVO();
        //获取班级信息
        ClassInfo classInfo = this.getById(classInfoId);
        if(ParamUtils.isEmpty(classInfo)){
            throw new BusinessException("班级不存在!");
        }
        msc.setOrganizationId(classInfo.getOrganizationId());
        msc.setCampusId(classInfo.getCampusId());
        msc.setProductId(classInfo.getProductId());
        msc.setClassName(classInfo.getClassName());
        msc.setClassStatus(classInfo.getClassStatus());
        //获取拼班明细信息
        LambdaQueryWrapper<SpellingClassDetails> scdWrap = new LambdaQueryWrapper<>();
        scdWrap.eq(SpellingClassDetails::getClassInfoId, classInfoId);
        scdWrap.eq(SpellingClassDetails::getDeleted, Boolean.FALSE);
        SpellingClassDetails spellingClassDetails = spellingClassDetailsMapper.selectOne(scdWrap);
        CourseSchedule courseSchedule = courseScheduleMapper.selectById(spellingClassDetails.getScheduleId());
        msc.setWeekCode(courseSchedule.getWeekCode());
        msc.setCourseType(courseSchedule.getCourseType());
        //获取商品信息
        Product product = productMapper.selectById(classInfo.getProductId());
        msc.setProductName(product.getProductName());
        msc.setCoverImage(product.getCoverImage());
        msc.setSpellType(spellingClassDetails.getSpellType());
        msc.setPrice(spellingClassDetails.getPrice());
        msc.setCourseId(classInfo.getCourseId());
        msc.setStartDate(spellingClassDetails.getStartDate());
        msc.setEndDate(spellingClassDetails.getEndDate());
        msc.setStartTime(spellingClassDetails.getStartPeriod());
        msc.setEndTime(spellingClassDetails.getEndPeriod());
        msc.setTotalNum(spellingClassDetails.getNum());
        msc.setWxUserId(classInfo.getWxUserId());
        ProductMinPriceVO pmpVo = productSellPriceRelMapper.queryProductMaxNum(product.getId());
        msc.setMaxNum(pmpVo.getMaxNum());
        if (classInfo.getWxUserId().equals(SecurityUtils.getAccountId())) {
            msc.setRegimentalCommander(Boolean.TRUE);
        }else {
            msc.setRegimentalCommander(Boolean.FALSE);
        }
        msc.setCourseScheduleDetailId(spellingClassDetails.getCourseScheduleDetailId());
        msc.setCourseScheduleId(spellingClassDetails.getScheduleId());
        msc.setSpellClassDetailsId(spellingClassDetails.getId());
        WxUser wxUser = wxUserService.getById(classInfo.getWxUserId());
        msc.setNickName(wxUser.getNickname());
        msc.setAvatar(wxUser.getAvatar());
        msc.setPhone(wxUser.getPhone());
        //查询学员信息
        List<WeChatUserVO> weChatUserList = studentMapper.findStudent(classInfoId);
        if (ParamUtils.isNotEmpty(weChatUserList)) {
            msc.setWeChatUserList(weChatUserList);
        }
        return msc;
    }

    /**
     * 移出学员
     *
     * @param dto 班级学生Id     学生Id
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeClassStudent(RemoveStudentDTO dto) throws ParseException {

        ClassInfo classInfo = this.getById(dto.getClassInfoId());
        if(!Objects.equals(classInfo.getClassStatus(),ClassInfoStatusEnum.IN_CLASS.getValue()) && !Objects.equals(classInfo.getClassStatus(),ClassInfoStatusEnum.FINISH_CLASS.getValue()) &&!Objects.equals(classInfo.getClassStatus(),ClassInfoStatusEnum.OPEN_CLASS.getValue())){
            throw new BusinessException("当前班级状态无效,无需移除学员");
        }
        if(!Objects.equals(dto.getWxUserId(),SecurityUtils.getAccountId())){
            throw new BusinessException("只能刪除自己的学员");
        }

        // 判断当前时间是否包含在周期内
        // 如 周期   7.5 -- 7.10
        // 1.假如当前时间为 7.4  既:当前时间在周期之前(取最近一条数据)根据course_date降序
        // 根据课表Id和当前时间查询课表详情 取最近一条数据
        List<String> studentIds = Lists.newArrayList();
        studentIds.add(dto.getStudentId());

        //当前时间
        LocalDate nowDate = LocalDate.now();
        SpellingClassDetails spellingClassDetails = spellingClassDetailsMapper.selectById(dto.getSpellClassDetailsId());
        List<CourseScheduleDetail> courseScheduleDetailList = Lists.newArrayList();
        //当前时间在周期之前
        if(nowDate.isBefore(date2LocalDate(spellingClassDetails.getStartDate())) || nowDate.isEqual(date2LocalDate(spellingClassDetails.getStartDate()))){
            // 根据课表Id和当前时间查询课表详情
            courseScheduleDetailList = courseScheduleDetailMapper.queryCourseScheduleDetailList(dto.getCourseScheduleId(),format(nowDate,YYYY_MM_DD));
            CourseScheduleDetail scheduleDetail = courseScheduleDetailList.stream().findFirst().get();
            if(ParamUtils.isEmpty(scheduleDetail)){
                throw new BusinessException("无需移除学员");
            }
            //移除学员相关操作
            exitClass(classInfo.getId(),studentIds);
            //移除学员、更新考勤、解除冻结
            // extractedRenew(dto, scheduleDetail,classInfo);
        }

        // 2.假如当前时间为 7.6 既:当前时间在周期之内(有值直接取数据,没有值走第一步操作)
        // 根据当前时间、课表Id和时段查询课表详情
        if(between(nowDate,date2LocalDate(spellingClassDetails.getStartDate()),date2LocalDate(spellingClassDetails.getEndDate()))){
            CourseScheduleDetail courseScheduleDetail = courseScheduleDetailMapper.getScheduleDetailList(dto.getCourseScheduleId(),format(nowDate,YYYY_MM_DD),spellingClassDetails.getStartPeriod(),spellingClassDetails.getEndPeriod());
            if(ParamUtils.isNotEmpty(courseScheduleDetail)){
                //移除学员相关操作
                exitClass(classInfo.getId(),studentIds);
                //移除学员、更新考勤、解除冻结
                // extractedRenew(dto,courseScheduleDetail,classInfo);
            }else{
                List<CourseScheduleDetail> courseScheduleDetailList2 = courseScheduleDetailMapper.queryCourseScheduleDetailList(dto.getCourseScheduleId(),format(nowDate,YYYY_MM_DD));
                //courseScheduleDetail 取第一种
                CourseScheduleDetail scheduleDetail = courseScheduleDetailList2.stream().findFirst().get();
                if(ParamUtils.isEmpty(scheduleDetail)){
                    throw new BusinessException("无需移除学员");
                }
                //移除学员相关操作
                exitClass(classInfo.getId(),studentIds);
                //移除学员、更新考勤、解除冻结
                // extractedRenew(dto,scheduleDetail,classInfo);
            }
        }

    }

    /**
     * 移除学员、更新考勤、解除冻结
     *
     * @param dto            dto
     * @param scheduleDetail 课表详情
     */
    private void extractedRenew(RemoveStudentDTO dto, CourseScheduleDetail scheduleDetail,ClassInfo classInfo) {

        //拼班完成后移除就是首次课不能移 非首次课以冻结待考勤不能移
        // 班级拼班详情里的课表详情ID就是首次课
        //你当前移除的是哪一天的就是哪条的
        // 如果当前移除这一天没有 那就是大于今天的第一条
        //查询订单
        LambdaQueryWrapper<Orders> orderWrapper = new LambdaQueryWrapper<>();
        orderWrapper.eq(Orders::getStudentId, dto.getStudentId());
        orderWrapper.eq(Orders::getScheduleDetailId, scheduleDetail.getId());
        // orderWrapper.eq(Orders::getOrderStatus, OrderStatusEnum.WAIT.getValue());
        Orders order = orderService.getOne(orderWrapper);
        if(ParamUtils.isNotEmpty(order)){
            if(OrderStatusEnum.WAIT.getValue().equals(order.getOrderStatus())){
                LambdaUpdateWrapper<ClassStudent> csWrapper = new LambdaUpdateWrapper<>();
                csWrapper.eq(ClassStudent::getClassInfoId,order.getClassId());
                csWrapper.eq(ClassStudent::getStudentId,order.getStudentId());
                csWrapper.set(ClassStudent::getStayRemove,Boolean.TRUE);
                //更新
                classStudentService.update(csWrapper);
            }

        }
        //更新班级学员表
        ClassStudent classStudent = classStudentService.getById(dto.getClassStudentId());
        classStudent.setExitTime(new Date());
        classStudent.setActive(Boolean.FALSE);
        classStudentService.updateById(classStudent);
        // 更新course_schedule_detail 表 due_num减一
        CourseScheduleDetail courseScheduleDetail = courseScheduleDetailMapper.selectById(scheduleDetail.getId());
        courseScheduleDetail.setDueNum(courseScheduleDetail.getDueNum() - 1);
        courseScheduleDetailMapper.updateById(courseScheduleDetail);
        StudentAttendance studentAttendance = studentAttendanceMapper.findStudentAttendance(dto.getClassStudentId(),
            scheduleDetail.getId());

        //班级课表due_num-1
        SpellingClassPeriod period = this.spellingClassPeriodService.period(dto.getClassInfoId(), scheduleDetail.getId());
        if(ParamUtils.isNotEmpty(period)){
            period.setDueNum(period.getDueNum() - 1);
            this.spellingClassPeriodService.updateById(period);
        }

        //更新考勤记录
        studentAttendanceMapper.updateStudentAttendance(dto.getClassStudentId(), scheduleDetail.getId());
        if(ParamUtils.isNotEmpty(studentAttendance)){
            // 解冻金额
            orderService.cancelOrder(studentAttendance.getOrderId());
        }
    }

    /**
     * 通过课程ID获取班级风采
     *
     * @param classId
     * @return
     */
    public List<ClassMienVO> getMienByClass(String classId) {
        List<ClassMien> classMienList = classMienMapper.selectList(new LambdaQueryWrapper<ClassMien>()
            .eq(ClassMien::getClassInfoId, classId));
        if(CollectionUtils.isEmpty(classMienList)){
            return null;
        }
        //根据list查时间
        Map<String, Date> idToDate = courseScheduleDetailMapper.selectList(new LambdaQueryWrapper<CourseScheduleDetail>()
            .in(CourseScheduleDetail::getId, classMienList.stream().map(ClassMien::getScheduleDetailId).collect(Collectors.toList()))).stream()
            .collect(Collectors.toMap(CourseScheduleDetail::getId, CourseScheduleDetail::getCourseDate));
        List<ClassMienVO> classMienVOS = BeanCopyUtil.copyListProperties(classMienList, ClassMienVO::new);
        classMienVOS.forEach(i->{
            i.setScheduleDetailDate(idToDate.get(i.getScheduleDetailId()));
        });
        return classMienVOS;
    }


    /**
     * 判断是否是教练
     * @return
     */
    public WxUser checkStaff(){
        WxUser wxUser = wxUserService.list(new LambdaQueryWrapper<WxUser>().eq(WxUser::getId, SecurityUtils.getAccountId()))
            .stream().findFirst().orElseThrow(() -> new BusinessException("当前用户信息异常"));
        return wxUser;
    }

    /**
     * 通过家长账号找班级列表
     * @return
     */
    public List<String> getClassByUser(){
        List<String> studentIds = userStudentRelMapper.selectList(new LambdaQueryWrapper<UserStudentRel>()
            .eq(UserStudentRel::getUserId, SecurityUtils.getAccountId())).stream().map(UserStudentRel::getStudentId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(studentIds)){
            return Arrays.asList("不存在");
        }
        return classStudentMapper.selectList(new LambdaQueryWrapper<ClassStudent>().in(ClassStudent::getStudentId, studentIds)).stream().map(ClassStudent::getClassInfoId).collect(Collectors.toList());
    }
    /**
     * 微信获取班级列表
     * @param isCoach 是否教练
     * @return
     */
    public List<ClassWxPageVO> getWxClassList(Boolean isCoach) {
        List<ClassWxDetailVO> coll=new ArrayList<>();

        if(!isCoach){
            //会员
            //获取拼过班的班级列表
            List<ClassWxDetailVO> wxClassList=coll;
            List<String> classByUser = getClassByUser();
            if(CollectionUtils.isNotEmpty(classByUser)){
                wxClassList = classInfoMapper.getWxClassList(classByUser, null, false, null);
            }
            //获取发起拼团的班级
            List<ClassWxDetailVO> classWxDetailVO = classInfoMapper.getWxClassList(null, null, false, SecurityUtils.getAccountId());
            wxClassList.addAll(classWxDetailVO);
            coll=wxClassList.stream().sorted(Comparator.comparing(ClassWxDetailVO::getCompleteTime,Comparator.nullsFirst(Date::compareTo)).reversed()).collect(Collectors.toList());
        }else{
            //教练
            Coach coach = coachMapper.selectList(new LambdaQueryWrapper<Coach>().eq(Coach::getWxUserId,SecurityUtils.getAccountId())).stream().findFirst().orElseThrow(()->new BusinessException("该教练不存在"));
            coll = classInfoMapper.getWxClassList(null,coach.getOrganizationId(),true,null);
        }
        //去重
        List<ClassWxDetailVO> wxClassPage = coll.stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(wxClassPage)) {
            return new ArrayList<ClassWxPageVO>();
        }
        List<ClassWxPageVO> result = BeanCopyUtil.copyListProperties(wxClassPage, ClassWxPageVO::new);

        //下节课
        //获取classID集合
        List<String> classIdList = wxClassPage.stream().map(ClassWxDetailVO::getClassId).collect(Collectors.toList());
        Map<String, List<SpellingClassPeriod>> nextClassTime = getNextClassTime(classIdList);
        if(nextClassTime==null){
            return result;
        }
        result.forEach(i->{
            List<SpellingClassPeriod> spellingClassPeriods = nextClassTime.get(i.getClassId());
            if(CollectionUtils.isNotEmpty(spellingClassPeriods)){
                SpellingClassPeriod spellingClassPeriod = spellingClassPeriods.stream()
                    .filter(j -> j.getStatus().equals(SpellingClassPeriodEnum.NO_EXPIRED.getValue()))
                    .sorted(Comparator.comparing(SpellingClassPeriod::getCourseDate))
                    .findFirst().orElse(null);
                if(spellingClassPeriod!=null){
                    //转类型
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
                    i.setNextCLassTime(dateFormat.format(spellingClassPeriod.getCourseDate())+" "+timeFormat.format(spellingClassPeriod.getStartTime()));
                }
            }
        });
        //排序
        //        List<ClassWxPageVO> collect = result.stream().sorted(Comparator.comparing(ClassWxPageVO::getCompleteTime,Comparator.nullsFirst(Date::compareTo)).reversed()).collect(Collectors.toList());
        return result;
    }

    /**
     * 根据ClassId获取下节课时间
     * @param classIdList
     * @return
     */
    public Map<String, List<SpellingClassPeriod>> getNextClassTime(List<String> classIdList){
        List<SpellingClassPeriod> nextTimeList = spellingClassPeriodService.list(new LambdaQueryWrapper<SpellingClassPeriod>()
            .in(SpellingClassPeriod::getClassInfoId, classIdList));

        //如果没有关联，则直接返回null,前端显示已结课;
        if(CollectionUtils.isEmpty(nextTimeList)){
            return null;
        }
        //班级id对应的拼班时段表的时间
        Map<String, List<SpellingClassPeriod>> classIdToNextTimeMap = nextTimeList.stream().collect(Collectors.groupingBy(SpellingClassPeriod::getClassInfoId));
        return classIdToNextTimeMap;
    }

    /**
     * 教练端获取班级列表
     *
     * @return
     */
    public List<CoachClassPageVO> getCoachClassList() {
        WxUser wxUser = checkStaff();
        if (!wxUser.getIsCoach()) {
            throw new BusinessException("员工信息不存在");
        }
        List<ClassWxPageVO> wxClassPage = getWxClassList(true);
        //筛选属于教练的班级
        Coach coach = coachMapper.selectList(new LambdaQueryWrapper<Coach>().eq(Coach::getWxUserId, wxUser.getId()))
            .stream().findFirst().orElseThrow(() -> new BusinessException("员工信息不存在"));
        List<ClassWxPageVO> staffList = wxClassPage
            .stream()
            .filter(i -> coach.getId().equals(i.getCoachId()))
            .collect(Collectors.toList());
        ArrayList<CoachClassPageVO> resultList = new ArrayList<>();
        //根据地区名分组
        Map<String, List<ClassWxPageVO>> campusNameMap = staffList.stream().collect(Collectors.groupingBy(ClassWxPageVO::getCampusName));
        campusNameMap.forEach((key, value) -> {
            CoachClassPageVO coachClassPageVO = new CoachClassPageVO();
            coachClassPageVO.setCampusName(key);
            coachClassPageVO.setClassWxPageVOList(value);
            resultList.add(coachClassPageVO);
        });
        return resultList;
    }

    /**
     * 获取微信班级详情信息
     * @param classId
     * @return
     */
    public ClassWxDetailVO getWxClassDetail(String classId,Boolean isCoach) {
        ClassWxDetailVO wxClass = classInfoMapper.getWxClassList(Arrays.asList(classId),null,isCoach,null).stream().findFirst().orElse(null);
        if (wxClass == null) {
            return null;
        }
        //判断当前用户是否为团长
        ClassInfo classInfo = Optional.ofNullable(classInfoMapper.selectById(classId)).orElseThrow(()->new BusinessException("当前班级不存在"));
        if (classInfo.getWxUserId().equals(SecurityUtils.getAccountId())) {
            wxClass.setIsBoss(true);
        }else {
            wxClass.setIsBoss(false);
        }
        wxClass.setStudentVOList(new ArrayList<StudentVO>());
        //根据classID获取学生ID集合
        List<ClassStudent> studentIdList = classStudentService.list(new LambdaQueryWrapper<ClassStudent>()
            .eq(ClassStudent::getClassInfoId, classId)
            .eq(ClassStudent::getActive,true));
        if (CollectionUtils.isEmpty(studentIdList)) {
            return wxClass;
        }
        //根据学生ID集合获取学生信息
        List<Student> students = studentMapper.selectList(new LambdaQueryWrapper<Student>()
            .in(Student::getId, studentIdList.stream().map(ClassStudent::getStudentId).collect(Collectors.toList())));
        if (CollectionUtils.isNotEmpty(students)) {
            List<StudentVO> studentVOS = BeanCopyUtil.copyListProperties(students, StudentVO::new);
            //如果是教练，则在每个学员头上标注余额是否充足
            if(isCoach){
                //这里的key为学生ID ,value值为家长ID，
                Map<String, String> accByStudentIdToMap = getAccByStudentIdToMap(studentVOS.stream().map(StudentVO::getId).collect(Collectors.toList()));

                //通过用户ID查找学生list集合（主要是想要其list的size大小）
                Map<String, List<UserStudentRel>>  userIdToMap = getStudentListByAcc(wxClass.getClassId(), accByStudentIdToMap.values().stream().distinct().collect(Collectors.toList()))
                    .stream().collect(Collectors.groupingBy(UserStudentRel::getUserId));
                //通过学员ID集合与班级iD查询评价表
                List<EducationEvaluationRecord> educationEvaluationRecords = educationEvaluationRecordMapper.selectList(new LambdaQueryWrapper<EducationEvaluationRecord>()
                    .eq(EducationEvaluationRecord::getClassId, classId)
                    .in(EducationEvaluationRecord::getStudentId, studentVOS.stream().map(StudentVO::getId).collect(Collectors.toList())));

                //每个家长的账户余额用map装
                Map<String, BigDecimal> userIdToMoneyMap = wxUserPurseService.getMyPurse(accByStudentIdToMap.values().stream().distinct().collect(Collectors.toList()))
                    .stream().collect(Collectors.toMap(WxUserPurse::getWxUserId, WxUserPurse::getTotalAmount));
                studentVOS.forEach(i->{
                    //获取每个学员与家长的关系，并且挑出在此班级的家长学员数量大于1的，要乘倍数
                    //获取当前学生的UserId
                    String userId = accByStudentIdToMap.get(i.getId());
                    //通过UserId去查找当前班级存在几个学生，如果存在多个乘于倍数
                    BigDecimal multiply = wxClass.getPrice().multiply(new BigDecimal(userIdToMap.get(userId).size()));
                    //当前余额
                    BigDecimal bigDecimal = userIdToMoneyMap.get(userId);
                    //找不到时，默认钱包为空
                    if (bigDecimal == null) {
                        bigDecimal=BigDecimal.ZERO;
                    }
                    if(bigDecimal.compareTo(multiply)==-1){
                        i.setIsSufficient(false);
                    }else{
                        i.setIsSufficient(true);
                    }
                    //判断学员是否已经评价过
                    List<EducationEvaluationRecord> collect = educationEvaluationRecords.stream().filter(j -> j.getStudentId().equals(i.getId())).collect(Collectors.toList());
                    if(CollectionUtils.isEmpty(collect)){
                        i.setIsEvaluate(false);
                    }else {
                        i.setIsEvaluate(true);
                    }
                });
            }else{
                //标注是否为当前用户自己的孩子
                //获取当前用户的孩子
                List<UserStudentRel> studentListByAcc = getStudentListByAcc(classId, Arrays.asList(SecurityUtils.getAccountId()));
                studentVOS.forEach(i->{
                    List<UserStudentRel> collect = studentListByAcc.stream().filter(j -> j.getStudentId().equals(i.getId())).collect(Collectors.toList());
                    if(CollectionUtils.isEmpty(collect)){
                        i.setIsChildren(false);
                    }else {
                        i.setIsChildren(true);
                    }
                    //学生头像修改，找到家长并且返回家长头像地址
                    String userId = userStudentRelMapper.selectList(new LambdaQueryWrapper<UserStudentRel>()
                        .eq(UserStudentRel::getStudentId, i.getId())).stream().findFirst().orElseThrow(() -> new BusinessException("学生与家长信息异常")).getUserId();
                    i.setHeadUrl(Optional.ofNullable(wxUserService.getById(userId)).orElseThrow(()->new BusinessException("家长不存在")).getAvatar());
                });


            }
            wxClass.setStudentVOList(studentVOS);
        }

        //获取最近一节课的时间
        Map<String, List<SpellingClassPeriod>> nextClassTime = getNextClassTime(Arrays.asList(classId));
        if(nextClassTime!=null){
            List<SpellingClassPeriod> spellingClassPeriods = nextClassTime.get(classId);
            if(CollectionUtils.isNotEmpty(spellingClassPeriods)){
                SpellingClassPeriod spellingClassPeriod = spellingClassPeriods.stream()
                    .filter(j -> j.getStatus().equals(SpellingClassPeriodEnum.NO_EXPIRED.getValue()))
                    .sorted(Comparator.comparing(SpellingClassPeriod::getCourseDate))
                    .findFirst().orElse(null);
                if(spellingClassPeriod!=null){
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    String date = dateFormat.format(spellingClassPeriod.getCourseDate());
                    SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
                    String time = timeFormat.format(spellingClassPeriod.getStartTime());
                    wxClass.setNextCLassTime(date+" "+time);
                }
            }
        }

        //如果是家长，查看当前学员有多少，在判断钱够不够
        if(!isCoach){
            List<UserStudentRel> studentListByAcc = getStudentListByAcc(wxClass.getClassId(), Arrays.asList(SecurityUtils.getAccountId()));
            BigDecimal multiply = wxClass.getPrice().multiply(new BigDecimal(studentListByAcc.size()));
            //当前余额
            BigDecimal bigDecimal = wxUserPurseService.getMyPurse(SecurityUtils.getAccountId()).getAllowAmount();
            if(bigDecimal.compareTo(multiply)==-1){
                wxClass.setIsSufficient(false);
            }else{
                wxClass.setIsSufficient(true);
            }
        }
        return wxClass;
    }

    /**
     * 通过studentID集合查询出来的账号ID，去关联为map集合
     * @param studentId
     * @return
     */
    public Map<String,String> getAccByStudentIdToMap(List<String> studentId){
        if(CollectionUtils.isEmpty(studentId)){
            throw new BusinessException("班级学员数量为零");
        }
        return userStudentRelMapper.selectList(new LambdaUpdateWrapper<UserStudentRel>().in(UserStudentRel::getStudentId,studentId))
            .stream()
            .collect(Collectors.toMap(UserStudentRel::getStudentId, UserStudentRel::getUserId));
    }

    /**
     * 根据当前账号找指定班级内存在的学生集合
     * @return
     */
    public List<UserStudentRel> getStudentListByAcc(String classId,List<String> accList){
        return wxUserMapper.getStudentListByAcc(classId, accList);
    }


    public SellClaRuleInfoVO spellClaRuleByClaId(String classId) {
        return this.classInfoMapper.spellClaRuleByClaId(classId);
    }


    public List<SellClaRuleInfoVO> spellClaRuleByClaIds(List<String> classId) {
        return this.classInfoMapper.spellClaRuleByClaIds(classId);
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean exitClass(String classId) throws ParseException {
        //校验班级是否存在
        Optional.ofNullable(getById(classId)).orElseThrow(()->new BusinessException("班级不存在"));
        //获取当前登陆者在这个班级的的学生集合
        List<UserStudentRel> studentListByAcc = getStudentListByAcc(classId, Arrays.asList(SecurityUtils.getAccountId()));
        if(CollectionUtils.isEmpty(studentListByAcc)){
            throw new BusinessException("当前未加入拼班");
        }
        List<String> studentIdList = studentListByAcc.stream().map(UserStudentRel::getStudentId).collect(Collectors.toList());
        return exitClass(classId,studentIdList);
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean exitClass(String classId,List<String> studentIds) throws ParseException {
        /**
         * 1 判断是否为首次课，如果是，再去判断首次课是否被考勤，如果未考勤，则不允许退出班级
         * 1.1 如果首次课已考勤，退出班级
         * 2 如果不是首次课，通过detailId和班级、学员找到订单，且订单状态不为5，如果找不到订单或者订单不是已付款，则直接退出班级
         * 2.1 如果找到的订单显示未付款，则调用取消订单的接口，然后退出班级
         * 3 退出班级包括记录连续次数，最后再判断是否解散班级
         */
        //找首次课：spelling_class_period表按日期created_date，排序找第一个，在跟classStudent表的schedule_detail_id比较，如果相等就是首次课
        //找考勤：考勤表student_attendance通过class_student_id与schedule_detail_id找。
        //订单表通过schedule_detail_id、class_id、student_id找，并且订单状态不等于5
        ClassInfo classInfo = Optional.ofNullable(getById(classId)).orElseThrow(() -> new BusinessException("班级不存在"));
        //判断要退出班级的学员是否属于当前用户的学员
        List<UserStudentRel> studentListByAcc = this.getStudentListByAcc(classId, Arrays.asList(SecurityUtils.getAccountId()));
        studentIds.forEach(i->{
            List<UserStudentRel> collect = studentListByAcc
                .stream().filter(j -> (j.getStudentId().equals(i))).collect(Collectors.toList());
            if(CollectionUtils.isEmpty(collect)){
                throw new BusinessException("请选择该账户下的学员");
            }
        });

        //通过学生ID找classStudentID
        Map<String, String> sIdToCSId = classStudentService.list(new LambdaQueryWrapper<ClassStudent>()
            .in(ClassStudent::getStudentId, studentIds)
            .eq(ClassStudent::getClassInfoId, classId)
            .eq(ClassStudent::getActive,true))
            .stream().collect(Collectors.toMap(ClassStudent::getStudentId, ClassStudent::getId));
        //找当前时间的schedule_detail_id
        SimpleDateFormat currDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date currDate = currDateFormat.parse(currDateFormat.format(new Date()));
        SpellingClassPeriod spellingClassPeriod = spellingClassPeriodService.list(new LambdaQueryWrapper<SpellingClassPeriod>()
            .eq(SpellingClassPeriod::getClassInfoId,classId)
            .ge(SpellingClassPeriod::getCourseDate, currDate)
            .orderByAsc(SpellingClassPeriod::getCourseDate))
            .stream().findFirst().orElseThrow(()->new BusinessException("已无下节课课表"));
        String courseScheduleDetailId = spellingClassPeriod.getCourseScheduleDetailId();
        //获取考勤表集合（后续通过filter过滤出学生想要的考勤表）
        List<StudentAttendance> studentAttendances = studentAttendanceMapper.selectList(new LambdaQueryWrapper<StudentAttendance>()
            .in(StudentAttendance::getClassStudentId, sIdToCSId.values())
            .eq(StudentAttendance::getScheduleDetailId, courseScheduleDetailId));
        //找到订单表
        List<Orders> orders =Optional.ofNullable(orderService.list(new LambdaQueryWrapper<Orders>()
            .eq(Orders::getClassId, classId)
            .in(Orders::getStudentId, studentIds)
            .ne(Orders::getOrderStatus,"5"))).orElse(new ArrayList<Orders>());;

        studentIds.forEach(i->{
            //订单
            //找订单
            Orders currOrder = orders.stream().filter(j -> (j.getStudentId().equals(i))&&j.getScheduleDetailId().equals(courseScheduleDetailId))
                .findFirst().orElse(null);
            if(currOrder!=null){
                if(currOrder.getOrderStatus().equals(OrderStatusEnum.ALREADY.getValue())){
                    //查看是否已考勤
                    List<StudentAttendance> collect = studentAttendances.stream()
                        .filter(j -> (j.getAttendanceStatus().equals("0")&& (j.getClassStudentId().equals(sIdToCSId.get(i)))))
                        .collect(Collectors.toList());
                    if(CollectionUtils.isNotEmpty(collect)&&!classInfo.getClassStatus().equals(ClassInfoStatusEnum.IN_CLASS.getValue())){
                        throw new BusinessException("拼班成功首节课已支付，暂无法退出");
                    }
                }
            }
            //直接找订单集合，退掉全部待支付的
            List<Orders> orderList = Optional.ofNullable(orderService.list(new LambdaQueryWrapper<Orders>().eq(Orders::getStudentId, i)
                .eq(Orders::getClassId, classId))).orElse(null);
            if(CollectionUtils.isNotEmpty(orderList)){
                orderList.forEach(aa->{
                    if (aa.getOrderStatus().equals(OrderStatusEnum.WAIT.getValue())) {
                        orderService.cancelOrder(aa.getId());
                    }
                });
            }
        });

        //要退出学员的数量
        Integer studentCount = studentIds.size();
        classInfo.setUseStudentNum(classInfo.getUseStudentNum()-studentCount);
        //修改已拼学员
        if (!updateById(classInfo)) {
            throw new BusinessException("修改已拼学员失败");
        }

        //退出班级
        classStudentService.exitStudent(classId,studentIds);
        //修改学员数量
        ClassInfo newClassInfo = Optional.ofNullable(getById(classId)).orElseThrow(() -> new BusinessException("班级不存在"));
        //修改SpellingClassPeriod表
        List<SpellingClassPeriod> spellingClassPeriods = spellingClassPeriodService.list(new LambdaQueryWrapper<SpellingClassPeriod>()
            .eq(SpellingClassPeriod::getClassInfoId, classId)
            .eq(SpellingClassPeriod::getStatus, "1")
            .ne(SpellingClassPeriod::getDueNum,0));
        spellingClassPeriods.forEach(i->{
            if(i.getDueNum()>0){
                i.setDueNum(newClassInfo.getUseStudentNum());
            }
        });
        spellingClassPeriodService.updateBatchById(spellingClassPeriods);

        //反复确认过了这边不判断人数是否小于最低开班人数

//        //排除正在拼班中最小人数的校验
//        if(!newClassInfo.getClassStatus().equals(ClassInfoStatusEnum.IN_CLASS.getValue())){
//            //调取minNum，查看是否小于最小开班条件
//            Integer minNum = classInfoMapper.getMinNumByClassInfoId(newClassInfo.getId());
//            //如果超出限制，连续次数+1，后面判断是否解散班级
//            if (minNum > newClassInfo.getUseStudentNum()) {
//                newClassInfo.setConsecutiveNum(newClassInfo.getConsecutiveNum() + 1);
//                updateById(newClassInfo);
//
//                /**
//                 * 当天是否作废，如果作废，找下一天未作废的第一条
//                 * 如果不作废，找当天的考勤，如果待考勤，就把当天的传进来。
//                 * 判断当天是否已考勤，如果已考勤不调这个方法，
//                 *
//                 */
//                String scheduleDetailId = null;
//                if (spellingClassPeriod.getClassAttendanceStatus().equals(ScheduleDetailStatusEnum.CANCEL.getValue())){
//                    //查询大于  spellingClassPeriod.getCourseDate() 非作废未过期的第一次课
//                    SpellingClassPeriod earliestCurrentCanUsePeriod = spellingClassPeriodService.getEarliestCurrentCanUsePeriod(classId, spellingClassPeriod.getCourseDate());
//                    if(earliestCurrentCanUsePeriod!=null){
//                        scheduleDetailId=earliestCurrentCanUsePeriod.getCourseScheduleDetailId();
//                    }
//                }else {
//                    if (spellingClassPeriod.getClassAttendanceStatus().equals(ScheduleDetailStatusEnum.WAIT_ATTENDANCE.getValue())){
//                        scheduleDetailId = spellingClassPeriod.getCourseScheduleDetailId();
//                    }
//                }
//
//                if (ParamUtils.isNotEmpty(scheduleDetailId)){
//                    this.spellingClassPeriodService.cancelPeriod(ScheduleDetailStatusEnum.CANCEL.getValue(), courseScheduleDetailId, classId, CANCEL_REASON);
//                }
//            }
//            DetermineClassDisbanded(classId);
//        }else {
//            //统计全部
            courseScheduleDetailService.recountDueNum();
//        }

        return true;
    }
    /**
     * String scheduleDetailId = null;
     *                 if (spellingClassPeriod.getClassAttendanceStatus().equals(ScheduleDetailStatusEnum.CANCEL.getValue())) {
     *                     //查询大于  spellingClassPeriod.getCourseDate() 非作废未过期的第一次课
     *
     * //                    scheduleDetailId  = 非作废未过期的第一次课的courseScheduleDetailId;
     *
     *                 } else {
     *
     *                     if (spellingClassPeriod.getClassAttendanceStatus().equals(ScheduleDetailStatusEnum.WAIT_ATTENDANCE.getValue())){
     *                         scheduleDetailId = spellingClassPeriod.getCourseScheduleDetailId();
     *                     }
     *
     *                 }
     *
     *                 if (ParamUtils.isNotEmpty(scheduleDetailId)){
     *                     //作废本次可课表
     *
     *                     this.spellingClassPeriodService.cancelPeriod(ScheduleDetailStatusEnum.CANCEL.getValue(), courseScheduleDetailId, classId, CANCEL_REASON);
     *                 }
     */

    /**
     * 退出班级的时候判断班级是否解散
     * @return
     */
    public void DetermineClassDisbanded(String classId){
        String value = configService.getValueByType(SysConfigTypeEnum.B);
        Integer i = Integer.parseInt(value);
        ClassInfo classInfo = Optional.ofNullable(getById(classId)).orElseThrow(() -> new BusinessException("班级不存在"));
        if(i<=classInfo.getConsecutiveNum()){
            DissolutionClassDTO dissolutionClassDTO = new DissolutionClassDTO();
            dissolutionClassDTO.setClassId(classId);
            dissolutionClass(dissolutionClassDTO);
        }
    }

    /**
     * 校验拼班最小值，修改
     * @param classId
     */
    public void ModifyMinNum(String classId,List<String> studentIds,List<Orders> orders){
        ClassInfo classInfo = Optional.ofNullable(getById(classId)).orElseThrow(() -> new BusinessException("班级不存在"));
        //        //要退出学员的数量
        //        Integer studentCount = studentIds.size();
        //        classInfo.setUseStudentNum(classInfo.getUseStudentNum()-studentCount);
        //        //修改已拼学员
        //        if (!updateById(classInfo)) {
        //            throw new BusinessException("修改已拼学员失败");
        //        }
        //扣减相应课表详情（course_schedule_detail）的应到人数以及班级课表时段(spell_class_period)的应到人数
        //先查找是否存在订单，若不存在订单，就扣减
        //        for (String studentId : studentIds) {
        //            List<Orders> collect = orders.stream().filter(j -> j.getStudentId().equals(studentId)).collect(Collectors.toList());
        //            if(CollectionUtils.isEmpty(collect)){
        //                //如果这个学员找不到他对应的订单，则要退出的学员数量--
        //                studentCount--;
        //            }
        //        }
        //        List<Orders> ordersList = orderService.list(new LambdaQueryWrapper<Orders>().eq(Orders::getClassId, classId)
        //                .in(Orders::getStudentId, studentIds)
        //                .ne(Orders::getOrderStatus, OrderStatusEnum.CANCEL.getValue()));

        //        List<SpellingClassPeriod> spellingClassPeriods = spellingClassPeriodService.list(new LambdaQueryWrapper<SpellingClassPeriod>()
        //                .eq(SpellingClassPeriod::getClassInfoId, classId)
        //                .eq(SpellingClassPeriod::getStatus, "1"));
        //        if(CollectionUtils.isNotEmpty(spellingClassPeriods)){
        //            studentIds.forEach(j->{
        //                //应到人数减去退出的学员数量
        //                for (SpellingClassPeriod spellingClassPeriod : spellingClassPeriods) {
        //                    List<Orders> collect = orders.stream().filter(i -> (i.getScheduleDetailId()
        //                                    .equals(spellingClassPeriod.getCourseScheduleDetailId()))&&j.equals(i.getStudentId())).collect(Collectors.toList());
        //                    if(CollectionUtils.isNotEmpty(collect)){
        //
        //                        if(spellingClassPeriod.getDueNum()-1>=0){
        //                            spellingClassPeriod.setDueNum(spellingClassPeriod.getDueNum()-1);
        //                        }
        //                    }
        //                }
        //            });
        //
        //            //修改spell_class_period的应到人数
        //            spellingClassPeriodService.updateBatchById(spellingClassPeriods);
        //            List<String> courseScheduleDetailIds = spellingClassPeriods.stream().map(SpellingClassPeriod::getCourseScheduleDetailId).collect(Collectors.toList());
        //            //通过spelling_class_period的course_schedule_detail_id找到course_schedule_detail,修改应到人数due_num
        //            List<CourseScheduleDetail> courseScheduleDetails = courseScheduleDetailService.list(new LambdaQueryWrapper<CourseScheduleDetail>()
        //                    .in(CourseScheduleDetail::getId, courseScheduleDetailIds));
        //            studentIds.forEach(j->{
        //                for (CourseScheduleDetail courseScheduleDetail : courseScheduleDetails) {
        //                    List<Orders> collect = orders.stream()
        //                            .filter(i -> (i.getScheduleDetailId().equals(courseScheduleDetail.getId()))&&j.equals(i.getStudentId())).collect(Collectors.toList());
        //                    if(CollectionUtils.isNotEmpty(collect)){
        //                        if(courseScheduleDetail.getDueNum()-1>=0){
        //                            courseScheduleDetail.setDueNum(courseScheduleDetail.getDueNum()-1);
        //                        }
        //                    }
        //                }
        //            });
        //
        //            courseScheduleDetailService.updateBatchById(courseScheduleDetails);
        //        }

        //        //如果是开班中，就不执行扣除
        //        if(!classInfo.getClassStatus().equals(ClassInfoStatusEnum.IN_CLASS.getValue())) {
        //            //重新查询更新classInfo表
        //            ClassInfo newClassinfo = Optional.ofNullable(getById(classId)).orElseThrow(() -> new BusinessException("班级不存在"));
        //            //调取minNum，查看是否小于最小开班条件
        //            Integer minNum = classInfoMapper.getMinNumByClassInfoId(classId);
        //            //如果超出限制，连续次数+1，后面判断是否解散班级
        //            if (minNum > newClassinfo.getUseStudentNum()) {
        //                newClassinfo.setConsecutiveNum(newClassinfo.getConsecutiveNum() + 1);
        //            }
        //        }
    }

    /**
     * 班级列表获取教练的评价
     * @param dto 入参
     * @return 教练评价
     */
    public CoachEvaluateVO getEvaluate(CoachEvaluateDTO dto) {
        return this.educationEvaluationRecordMapper.getEvaluate(dto);
    }

    /**
     * (团长)解散 拼班
     *
     * @param disbandClassDTO 解散dto类
     * @return {@link Boolean}
     */
    @Transactional(rollbackFor = Exception.class)
    public void disbandClass(DisbandClassDTO disbandClassDTO) {

        ClassInfo classInfo = getById(disbandClassDTO.getClassId());
        if (classInfo == null) {
            throw new BusinessException("班级不存在");
        }
        // 如果classInfo中的wx_user_id属于当前操作用户的ID，则就是团长解散班级
        if (!classInfo.getWxUserId().equals(SecurityUtils.getAccountId())) {
            throw new BusinessException("不是团长不能解散班级!");
        }
        classInfo.setClassStatus(ClassInfoStatusEnum.DISSOLVE_CLASS_COLONEL.getValue());
        updateById(classInfo);
        // 修改class_student表
        List<ClassStudent> classStudent = classStudentService.list(new LambdaQueryWrapper<ClassStudent>().eq(ClassStudent::getClassInfoId, disbandClassDTO.getClassId()));
        classStudent.forEach(e -> {
            e.setExitTime(new Date());
            e.setActive(false);
        });
        classStudentService.updateBatchById(classStudent);
        //解散班级释放教练
        //根据班级Id查询班级拼班时段表(获取课表时段明细表Id)
        freedCoach(classInfo);

        //根据班级Id查询班级拼班时段表
        LambdaQueryWrapper<SpellingClassPeriod> spellingClassPeriodWrapper = new LambdaQueryWrapper<>();
        spellingClassPeriodWrapper.eq(SpellingClassPeriod::getClassInfoId,classInfo.getId());
        spellingClassPeriodWrapper.eq(SpellingClassPeriod::getClassAttendanceStatus,
            ScheduleDetailStatusEnum.WAIT_ATTENDANCE.getValue());
        List<SpellingClassPeriod> classPeriodList = spellingClassPeriodService.list(spellingClassPeriodWrapper);
        if(ParamUtils.isNotEmpty(classPeriodList)){
            for (SpellingClassPeriod spellingClassPeriod : classPeriodList) {
                spellingClassPeriod.setClassAttendanceStatus(ScheduleDetailStatusEnum.CANCEL.getValue());
                spellingClassPeriod.setDueNum(0);
                spellingClassPeriodService.updateById(spellingClassPeriod);
            }
            //重新统计应到人数
            courseScheduleDetailService.recountDueNum();
        }

        //取消班级中待支付的订单
        orderService.cancelOrderByClass(classInfo.getId());
        //班级解散：团长解散
        messageNotifyService.classDissolvedDueDate(classInfo.getId(), MessageTypeEnum.CLASS_DISSOLVED_GIRTH);
    }

    /**
     * 释放教练
     *
     * @param classInfo 班级
     */
    public void freedCoach(ClassInfo classInfo) {
        LambdaQueryWrapper<SpellingClassPeriod> scp = new LambdaQueryWrapper<>();
        scp.eq(SpellingClassPeriod:: getClassInfoId, classInfo.getId());
        List<SpellingClassPeriod> spellingClassPeriodList = spellingClassPeriodService.list(scp);
        //根据班级Id查询spelling_class_details
        LambdaQueryWrapper<SpellingClassDetails> scdWrap = new LambdaQueryWrapper<>();
        scdWrap.eq(SpellingClassDetails::getClassInfoId,classInfo.getId());
        SpellingClassDetails spellingClassDetails = spellingClassDetailsMapper.selectOne(scdWrap);
        if(ParamUtils.isNotEmpty(spellingClassDetails)){
            //查询课表详情
            CourseScheduleDetail courseScheduleDetail = courseScheduleDetailMapper.selectById(spellingClassDetails.getCourseScheduleDetailId());

            List<CourseScheduleDetail> list = courseScheduleDetailMapper.queryCourseScheduleDetails(courseScheduleDetail.getScheduleId(),courseScheduleDetail.getSectionCode(),TimeUtils.toText(courseScheduleDetail.getCourseDate(),YYYY_MM_DD));
            if(ParamUtils.isNotEmpty(list)){
                CourseScheduleDetail csd = list.get(0);
                //更新教练状态(可用)
                String startPeriod = TimeUtils.toText(csd.getStartTime(), DateUtils.HH_MM);
                String endPeriod = TimeUtils.toText(csd.getEndTime(), DateUtils.HH_MM);
                List<String> courseDates =  Lists.newArrayList();
                courseDates.add(DateUtils.dateTime(csd.getCourseDate()));
                courseScheduleDetailCoachRelMapper.updateCoachRelStatus(classInfo.getCoachId(),startPeriod,endPeriod,courseDates,true);
            }

        }

        if(CollectionUtils.isNotEmpty(spellingClassPeriodList)){
            SpellingClassPeriod spellingClassPeriod = spellingClassPeriodList.get(0);
            String startPeriod = TimeUtils.toText(spellingClassPeriod.getStartTime(), DateUtils.HH_MM);
            String endPeriod = TimeUtils.toText(spellingClassPeriod.getEndTime(), DateUtils.HH_MM);
            List<String> cycle = spellingClassPeriodList.stream().map(item->DateUtils.dateTime(item.getCourseDate())).collect(Collectors.toList());
            //更新教练状态(可用)
            courseScheduleDetailCoachRelMapper.updateCoachRelStatus(classInfo.getCoachId(),startPeriod,endPeriod,cycle,true);
        }
    }

    public List<ClassScheduleVO> findClassSchedule() {
        return classInfoMapper.findClassSchedule();
    }

    /**
     * 解散班级(人数不足)
     *
     * @param dissolutionClassDTO 解散dto类
     */
    @Transactional(rollbackFor = Exception.class)
    public void dissolutionClass(DissolutionClassDTO dissolutionClassDTO) {

        ClassInfo classInfo = getById(dissolutionClassDTO.getClassId());
        if (classInfo == null) {
            throw new BusinessException("班级不存在");
        }
        if(ClassInfoStatusEnum.IN_CLASS.getValue().equals(classInfo.getClassStatus())){
            classInfo.setClassStatus(ClassInfoStatusEnum.FAIL_CLASS.getValue());
        }else {
            classInfo.setClassStatus(ClassInfoStatusEnum.DISSOLVE_CLASS_DEFICIENCY.getValue());
        }
        if (ParamUtils.isNotEmpty(dissolutionClassDTO.getOptBy())){
            classInfo.setLastModifiedBy(dissolutionClassDTO.getOptBy());
            classInfo.setLastModifiedDate(dissolutionClassDTO.getOptDate());
        }
        this.updateById(classInfo);
        // 修改class_student表
        List<ClassStudent> classStudent = classStudentService.list(new LambdaQueryWrapper<ClassStudent>().eq(ClassStudent::getClassInfoId, dissolutionClassDTO.getClassId()));
        classStudent.forEach(e -> {
            e.setExitTime(new Date());
            e.setActive(false);
            if (ParamUtils.isNotEmpty(dissolutionClassDTO.getOptBy())){
                e.setLastModifiedBy(dissolutionClassDTO.getOptBy());
                e.setLastModifiedDate(dissolutionClassDTO.getOptDate());
            }
        });
        //更新spelling_class_period表状态
        spellingClassPeriodService.updateSpellClassPeriodStatus(classInfo, dissolutionClassDTO.getOptBy(), dissolutionClassDTO.getOptDate());
        //统计全部
        courseScheduleDetailService.recountDueNum();
        //释放教练
        freedCoach(classInfo);
        classStudentService.updateBatchById(classStudent);
        //取消班级中待支付的订单
        orderService.cancelOrderByClass(classInfo.getId());
        //解散班级(人数不足)
        //messageNotifyService.classDissolvedDueDate(classInfo.getId(), MessageTypeEnum.CLASS_DISSOLVED_NO_ENOUGH);
    }


    /**
     * 新增风采
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean uploadMien (UploadMienDTO dto){
        ClassMien classMien = new ClassMien();
        BeanUtils.copyProperties(dto,classMien);
        if (classMienMapper.insert(classMien)<=0) {
            throw new BusinessException("插入失败");
        }
        return true;
    }
}
